import { defineConfig, loadEnv } from 'vite';
import type { UserConfig, ConfigEnv } from 'vite';
import { fileURLToPath } from 'url';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import { viteMockServe } from 'vite-plugin-mock';
import { visualizer } from 'rollup-plugin-visualizer';
import AutoImport from "unplugin-auto-import/vite";
import Icons from "unplugin-icons/vite";
import Components from "unplugin-vue-components/vite";
import IconsResolver from "unplugin-icons/resolver";
import ElementPlus from "unplugin-element-plus/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import postcssPxToViewport from 'postcss-px-to-viewport';
import brotli from 'rollup-plugin-brotli';
import ViteCompression from 'vite-plugin-compression';

export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
  // 获取当前工作目录
  const root = process.cwd();
  // 获取环境变量
  const env = loadEnv(mode, root);
  return {
    // 项目根目录 
    root,
    // 项目部署的基础路径
    base: '/',
    publicDir: fileURLToPath(new URL('./public', import.meta.url)), // 无需处理的静态资源位置
    assetsInclude: fileURLToPath(new URL('./src/assets', import.meta.url)), // 需要处理的静态资源位置
    // 预处理器配置
    css: {
      // vw 适配
      // postcss: {
      //   plugins: [
      //     postcssPxToViewport({
      //       unitToConvert: "px",  // 需要转换的单位
      //       viewportWidth: 1500,  // UI设计稿的宽度
      //       unitPrecision: 5,    // 转换后的精度，即小数点位数
      //       propList: ["*"],     // 指定转换的css属性的单位，*代表全部css属性的单位都进行转换
      //       viewportUnit: "vw",   // 指定需要转换成的视窗单位，默认vw
      //       fontViewportUnit: "vw",   // 字体使用的视窗单位
      //       selectorBlacklist: ["ignore-"],  / 指定不转换为视窗单位的类名，可以自定义，只要类名包含这个字符串即可
      //       minPixelValue: 1,   // 默认值1，小于或等于1px则不进行转换
      //       mediaQuery: false,  // 是否在媒体查询的css代码中也进行转换，默认false
      //       replace: true,   // 是否转换后直接更换属性值
      //       exclude: [],    // 设置忽略文件，用正则做目录名匹配
      //       landscape: false,  // 是否处理横屏情况
      //     })
      //   ]
      // },
      preprocessorOptions: {
        less: {
          additionalData: `@import '@/styles/variable.less';`
        }
      }
    },
    plugins: [
      // brotli({}), // Brotli 压缩插件 br压缩效率 >>> gzip
      // gzip 压缩插件
      ViteCompression({
        // 压缩算法
        algorithm: 'gzip', // 可选值：'gzip' | 'brotliCompress' | 'deflate' | 'deflateRaw'
        // 压缩文件的后缀名
        ext: '.gz',
        // 压缩级别 9最高
        threshold: 1024*20, // 只处理大于此大小的文件，单位为字节
      }),
      // Vue模板文件编译插件
      vue(),
      // jsx文件编译插件
      vueJsx(),
      // 开启mock服务器
      viteMockServe({
        // 如果接口为 /mock/xxx 以 mock 开头就会被拦截响应配置的内容
        mockPath: 'mock', // 数据模拟需要拦截的请求起始 URL
        enable: true // 本地环境是否开启 mock 功能
      }),
      // 开启ElementPlus自动引入CSS
      ElementPlus({}),
      // 自动引入组件及ICON
      AutoImport({
        imports: [
          'vue',  
          'vue-router', // 自动引入 vue-router 的相关函数
        ],
        resolvers: [IconsResolver(), ElementPlusResolver()],
         // 指定组件的类型定义文件位置
        dts: fileURLToPath(
          new URL("./types/auto-imports.d.ts", import.meta.url),
        ),
      }),
      // 自动注册组件
      Components({
        resolvers: [IconsResolver(), ElementPlusResolver()],
        // 指定组件的类型定义文件位置
        dts: fileURLToPath(
          new URL("./types/components.d.ts", import.meta.url),
        ),
        dirs: [fileURLToPath(new URL('./src/components/auto', import.meta.url))]
      }),
      // 自动安装图标
      Icons({
        autoInstall: true,
      }),
    ],
    // 运行后本地预览的服务器
    server: {
      // https配置
      // https: {}, 
      // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址，包括局域网和公网地址。
      host: true,
      // 开发环境预览服务器端口
      port: 3000,
      // 启动后是否自动打开浏览器
      open: false,
      // 是否开启CORS跨域
      cors: true,
      // 代理服务器
      // 帮助我们开发时解决跨域问题
      proxy: {
        // 代理配置
        // env.VITE_APP_API_BASEURL 和 env.VITE_APP_MOCK_BASEURL 分别是环境变量中定义的 API 基础 URL 和 Mock 基础 url
        [env.VITE_APP_API_BASEURL]: {
          target: 'http://localhost:9000',
          // 改变 Host Header
          changeOrigin: true
          // 发起请求时将 '/api' 替换为 ''
          //rewrite: (path) => path.replace(/^\/api/, ""),
        },
        [env.VITE_APP_MOCK_BASEURL]: {
          target: 'http://localhost:9000',
          // 改变 Host Header
          changeOrigin: true
          // 发起请求时将 '/api' 替换为 ''
          //rewrite: (path) => path.replace(/^\/api/, ""),
        }
      },
    },
    build: {
      // 关闭 sorcemap 报错不会映射到源码
      sourcemap: false,
      // 打包大小超出 500kb 提示警告
      chunkSizeWarningLimit: 500,
      rollupOptions: {
        // 打包入口文件 根目录下的 index.html
        input: {
          index: fileURLToPath(new URL('./index.html', import.meta.url)),
        },
        // 打包体积可视化
        plugins: [visualizer({ open: true })],
        // 打包输出目录
        output: {
          experimentalMinChunkSize : 30 *1024, // 分片最小大小 30kb  这个规则受 函数 副作用影响 看上去没生效 其实是生效了 
          // 静态资源分类打包  js、css、图片
          format: 'esm',
          chunkFileNames: 'static/js/[name]-[hash].js',
          entryFileNames: 'static/js/[name]-[hash].js',
          assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
          // 自定义分片
          manualChunks(id) {
            
            // id 是每个模块的绝对路径
            if (id.includes('node_modules')) {
              // 将所有来自 node_modules 的模块都打包到一个名为 'vendor' 的 chunk 中
              return 'vendor';
            }
            // 使用场景：node_modules中极少数页面使用另一个比较大的第三方库 如html2canvas、echarts等 单独进行分类打包
            // 也可以使用外链 cdn  安装 rollup-plugin-external-globals
            // 将globals 加到 rollupOptions.plugins 中    plugins: [visualizer({ open: true }), globals],

            // const globals = externalGlobals({
            //     moment: 'moment',
            //     'video.js': 'videojs',
            //     jspdf: 'jspdf',
            //     xlsx: 'XLSX',
            //     echart: 'echart'
            // });
            

            // if (id.includes('html2canvas')) {
            //   return 'html2canvas';
            // }
            // return 'index'; // 关系到入口文件的打包 其他模块将被打包到默认的 chunk 中 缺点：业务模块只要有变动 用户就得重新下载所有的代码 所有可以都分开打，遇到浏览器并发六个限制，开启http2

          },
        },
      },
    },
    // 配置别名
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url)),
        '#': fileURLToPath(new URL('./types', import.meta.url)),
      },
    },
  };
});